package com.ruoyi.web.service.insect.impl;

import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.domain.device.DeviceInfo;
import com.ruoyi.web.domain.insect.InsectRecord;
import com.ruoyi.web.domain.warning.FactorInfo;
import com.ruoyi.web.domain.warning.WarningInsect;
import com.ruoyi.web.domain.warning.WarningInsectRecord;
import com.ruoyi.web.enums.DeviceTypeEnum;
import com.ruoyi.web.enums.FactorEnum;
import com.ruoyi.web.enums.FunctionCodeEnum;
import com.ruoyi.web.enums.InsectWarningTypeEnum;
import com.ruoyi.web.middleware.influxdb.Influxdb2Service;
import com.ruoyi.web.pojo.dto.devicedata.DeviceFactorCountData;
import com.ruoyi.web.pojo.request.devicedata.DeviceFactorDataRequest;
import com.ruoyi.web.pojo.request.insect.InsectCountDataRequest;
import com.ruoyi.web.pojo.request.insect.InsectListRequest;
import com.ruoyi.web.pojo.request.insect.InsectTopRequest;
import com.ruoyi.web.pojo.vo.devicedata.DeviceContrastDataVO;
import com.ruoyi.web.pojo.vo.devicedata.DeviceFactorDataVO;
import com.ruoyi.web.pojo.vo.devicedata.DevicePhotoVO;
import com.ruoyi.web.pojo.vo.insect.*;
import com.ruoyi.web.service.device.DeviceInfoService;
import com.ruoyi.web.service.devicedata.DevicePhotoService;
import com.ruoyi.web.service.insect.InsectRecordService;
import com.ruoyi.web.service.insect.InsectSituationService;
import com.ruoyi.web.service.warning.FactorInfoService;
import com.ruoyi.web.service.warning.WarningInsectRecordService;
import com.ruoyi.web.service.warning.WarningInsectService;
import com.ruoyi.web.utils.influxdb.DeviceAggreDataParam;
import com.ruoyi.web.utils.influxdb.DeviceData;
import com.ruoyi.web.utils.v2.V2FactorInfo;
import com.ruoyi.web.utils.v2.V2RremoteCall;
import com.ruoyi.web.utils.wuqing.WQRremoteCall;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class InsectSituationServiceImpl implements InsectSituationService {

    @Autowired
    private InsectRecordService insectRecordService;

    @Autowired
    private WarningInsectRecordService warningInsectRecordService;

    @Autowired
    private DeviceInfoService deviceInfoService;

    @Autowired
    private WarningInsectService warningInsectService;

    @Autowired
    private DevicePhotoService devicePhotoService;

    @Autowired
    private Influxdb2Service influxdb2Service;

    @Autowired
    private FactorInfoService factorInfoService;

    @Override
    public List<InsectTopVO> getInsectTop(InsectTopRequest request){

        if(request.getDeviceIds() == null){
            request.setDeviceIds(deviceInfoService.getIdsByUser(DeviceTypeEnum.FL2.getValue()));
        }

        if(request.getDeviceIds().isEmpty()){
            return new ArrayList<>();
        }

        //识别记录
        List<InsectRecord> historyData = insectRecordService.getOriginHistoryData(request);

        //昆虫列表
        Map<String, WarningInsect> insectMap = warningInsectService.getAllMap();

        Map<String, Integer> resMap = historyData.stream().filter(rec -> {
            if (request.getInsectType() == null) {
                return true;
            }

            Integer type = Optional.ofNullable(insectMap.get(rec.getInsectName()))
                    .map(WarningInsect::getInsectType)
                    .orElse(4);

            return Objects.equals(type, request.getInsectType());
        }).collect(Collectors.groupingBy(InsectRecord::getInsectName, Collectors.summingInt(InsectRecord::getCount)));

        List<InsectTopVO> list = InsectTopVO.getList(resMap,insectMap);

        return list;
    }

    @Override
    public InsectAnalysisCountVO getInsectAnalysisCountVO(InsectListRequest request){

        InsectAnalysisCountVO result = new InsectAnalysisCountVO();

        if(request.getDeviceIds() == null){
            request.setDeviceIds(deviceInfoService.getIdsByUser(DeviceTypeEnum.FL2.getValue()));
        }

        if(request.getDeviceIds().isEmpty()){
            return result;
        }

        //查询当前年
        List<InsectAnalysisVO> currentYear = insectRecordService.getCountByInsectName(request);
        result.setCurrentYear(currentYear);

        //查询前一年
        request.changeTimePreviousYear();
        List<InsectAnalysisVO> previousYear = insectRecordService.getCountByInsectName(request);
        result.setPreviousYear(previousYear);

        //查询当前完整年的数据 -- 始见
        request.changeTimeCurrYearAll();
        List<InsectAnalysisVO> currYearAll = insectRecordService.getCountByInsectName(request);

        if(currYearAll.size() > 0){
            //当前年的始见数据
            InsectAnalysisVO firstVo = currYearAll.stream()
                    .sorted(Comparator.comparing(InsectAnalysisVO::getDay)).findFirst().get();

            result.setCurrentFirst(firstVo.getDay());
            result.setCurrentFirstNum(firstVo.getNums());

            //查询当前完整年的数据 -- 高峰
            InsectAnalysisVO peakVo = currYearAll.stream()
                    .sorted(Comparator.comparing(InsectAnalysisVO::getNums).reversed()).findFirst().get();

            //当前年的累计数据
            int sum = currYearAll.stream().mapToInt(InsectAnalysisVO::getNums).sum();

            result.setCurrentSum(sum);
            result.setCurrentPeak(peakVo.getDay());
            result.setCurrentPeakNum(peakVo.getNums());
        }

        //查询上一年完整年的数据 - 始见
        request.changeTimePreviousYearAll();
        List<InsectAnalysisVO> previousYearAll = insectRecordService.getCountByInsectName(request);

        if(previousYearAll.size() > 0){
            //上一年的始见数据
            InsectAnalysisVO prefirstVo = previousYearAll.stream()
                    .sorted(Comparator.comparing(InsectAnalysisVO::getDay)).findFirst().get();

            result.setPreviousFirst(prefirstVo.getDay());
            result.setPreviousFirstNum(prefirstVo.getNums());

            //查询上一年完整年的数据 - 高峰
            InsectAnalysisVO prePeakVo = previousYearAll.stream()
                    .sorted(Comparator.comparing(InsectAnalysisVO::getNums).reversed()).findFirst().get();

            //上一年的累计数据
            int sum = previousYearAll.stream().mapToInt(InsectAnalysisVO::getNums).sum();

            result.setPreviousSum(sum);
            result.setPreviousPeak(prePeakVo.getDay());
            result.setPreviousPeakNum(prePeakVo.getNums());
        }

        //查询常年数据
        request.changeTimeBeforeYear();
        List<InsectAnalysisVO> beforeYear = insectRecordService.getCountByInsectName(request);


        if(beforeYear.size() > 0){

            Map<Integer, List<InsectAnalysisVO>> beforeYearMap = beforeYear.stream().collect(Collectors.groupingBy(vo -> LocalDate.parse(vo.getDay()).getYear()));

            //常年高峰值
            List<Integer> beforePeakList = new ArrayList<>();

            //常年始见日期
            List<String> beforeFirstList = new ArrayList<>();

            //常年累计数据
            List<Integer> beforeSumList = new ArrayList<>();


            for (Integer integer : beforeYearMap.keySet()) {

                List<InsectAnalysisVO> yearVos = beforeYearMap.get(integer);

                //得到高峰数据
                InsectAnalysisVO peakVo = yearVos.stream()
                        .sorted(Comparator.comparing(InsectAnalysisVO::getNums).reversed()).findFirst().get();

                //得到始见数据
                InsectAnalysisVO firstVo = yearVos.stream()
                        .sorted(Comparator.comparing(InsectAnalysisVO::getDay)).findFirst().get();

                //每年的总和
                int sum = yearVos.stream().mapToInt(InsectAnalysisVO::getNums).sum();

                beforePeakList.add(peakVo.getNums());
                beforeFirstList.add(firstVo.getDay());
                beforeSumList.add(sum);
            }

            //常年平均
            int beforeAvg = beforeSumList.stream().mapToInt(Integer::intValue).sum() / beforeYearMap.keySet().size();
            result.setBeforeAvg(beforeAvg);

            //常年始见
            int beforeFirst = beforeFirstList.stream().mapToInt(date -> LocalDate.parse(date).getDayOfYear()).sum() / beforeYearMap.keySet().size();
            result.setBeforeFirst(beforeFirst);

            //常年高峰
            int beforePeak = beforePeakList.stream().mapToInt(Integer::intValue).sum() / beforeYearMap.keySet().size();
            result.setBeforePeakNum(beforePeak);
        }

        result.subtract(); // 计算差值
        return result;
    }

    @Override
    public List<DevicePhotoVO> getByInsectName(String deviceId, String time, String insectName){

        List<String> deviceIds = null;

        //获取设备id
        if(deviceId == null){
            deviceIds = deviceInfoService.getIdsByUser(DeviceTypeEnum.FL2.getValue());
        }else {
            deviceIds = Arrays.asList(deviceId.split(","));
        }

        List<DevicePhotoVO> result = new ArrayList<>();

        if(deviceIds.isEmpty()){
            return result;
        }

        for (String id : deviceIds) {
            List<DevicePhotoVO> photos = devicePhotoService.getByInsectName(id, time, insectName);
            result.addAll(photos);
        }

        result = result.stream().sorted(Comparator.comparing(DevicePhotoVO::getPicTime)).collect(Collectors.toList());

        return result;
    }

    @Override
    public List<DeviceInfo> getDeviceByFactor(String factorName){

        //查询账号下的气象和墒情设备
        List<DeviceInfo> weaDeviceIds = deviceInfoService.getByDeviceType(DeviceTypeEnum.FL5.getValue());
        List<DeviceInfo> moisDeviceIds = deviceInfoService.getByDeviceType(DeviceTypeEnum.FL1.getValue());
        moisDeviceIds.addAll(weaDeviceIds);

        if(moisDeviceIds.isEmpty()){
            return new ArrayList<>();
        }

        List<DeviceInfo> result = new ArrayList<>();

        for (DeviceInfo info : moisDeviceIds) {
            List<V2FactorInfo> factors = V2RremoteCall.getFactorByDid(info.getDeviceId());
            Set<String> factorKey = factors.stream().map(V2FactorInfo::getFactorKey).collect(Collectors.toSet());

            if(factorKey.contains(factorName)){
                result.add(info);
            }
        }

        return result;
    }


    @Override
    public List<FactorInfo> getFactorByUser(){
        //查询账号下的气象和墒情设备
        List<String> weaDeviceIds = deviceInfoService.getIdsByUser(DeviceTypeEnum.FL5.getValue());

        List<String> moisDeviceIds = deviceInfoService.getIdsByUser(DeviceTypeEnum.FL1.getValue());
        moisDeviceIds.addAll(weaDeviceIds);

        if(moisDeviceIds.isEmpty()){
            return new ArrayList<>();
        }

        String ids = moisDeviceIds.stream().collect(Collectors.joining(","));

        //查询设备列表
        List<FactorInfo> factor = this.getFactorById(ids);
        factor.sort(FactorInfo::compareTo);
        return factor;
    }

    @Override
    public List<FactorInfo> getFactorById(String deviceIds){
        List<FactorInfo> result = new ArrayList<>();

        if(deviceIds == null){
            return result;
        }

        //查询设备列表
        List<String> idList = Arrays.asList(deviceIds.split(","));
        List<DeviceInfo> deviceInfos = deviceInfoService.getByDeviceId(idList);

        if(deviceInfos.isEmpty()){
            return result;
        }

        Map<String, FactorInfo> factorMap = factorInfoService.getAllMap();

        Set<V2FactorInfo> resultFactor = new HashSet<>();

        //根据设备产品id获取物模型属性
        for (DeviceInfo device : deviceInfos) {
            List<V2FactorInfo> infos = V2RremoteCall.getFactorByDid(device.getDeviceId());
            if(infos != null){
                resultFactor.addAll(infos);
            }
        }

        //物模型转换为因子
        for (V2FactorInfo v2FactorInfo : resultFactor) {
            FactorInfo factorInfo = factorMap.get(v2FactorInfo.getFactorKey());
            if(factorInfo != null){
                result.add(factorInfo);
            }
        }

        //去重
        Map<String, FactorInfo> collect = result.stream().collect(Collectors.toMap(FactorInfo::getFactorKey, Function.identity(), (v1, v2) -> v1));
        result = new ArrayList<>(collect.values());

        result.sort(FactorInfo::compareTo);
        return result;
    }

    @Override
    public List<DeviceFactorDataVO> getFactorData(DeviceFactorDataRequest request){
        return WQRremoteCall.getFactorData(request);
    }

    @Override
    public HearderInsectVO getUserInsectCountData(InsectCountDataRequest request){

        List<String> deviceIds = deviceInfoService.getIdsByUser(DeviceTypeEnum.FL2.getValue());
        request.setDeviceIds(deviceIds);

        HearderInsectVO result = new HearderInsectVO();

        request.setEndTime(DateUtils.getTomorrowStr());

        if(request.getDateType() == 1){
            request.setStartTime(DateUtils.getAllBeginDate());
        }else if(request.getDateType() == 2){
            request.setStartTime(DateUtils.getYearBeginDate());
        }else if(request.getDateType() == 3){
            request.setStartTime(DateUtils.getMonthBeginDate());
        }else if(request.getDateType() == 4){
            request.setStartTime(DateUtils.getWeekBeginDate());
        }

        //查询虫情始见预警
        List<WarningInsectRecord> warningRecords = warningInsectRecordService.getByUserType(InsectWarningTypeEnum.FIRST.getValue());

        //查询识别记录,并计算前7种占比
        List<InsectCountDataVO> countData = insectRecordService.getUserInsectCountData(request);

        //昆虫列表
        Map<String, WarningInsect> insectMap = warningInsectService.getAllMap();

        //过滤昆虫类型
        countData = countData.stream().filter(rec -> {
            if (request.getInsectType() == null) {
                return true;
            }

            Integer type = Optional.ofNullable(insectMap.get(rec.getInsectName()))
                    .map(WarningInsect::getInsectType)
                    .orElse(4);

            return Objects.equals(type, request.getInsectType());
        }).collect(Collectors.toList());

        List<InsectCountDataVO> insectCountData = InsectRecordServiceImpl.computeCount(countData, 7);

        //处理始见期时间
        if(StringUtils.isNotEmpty(insectCountData)) {
            List<String> insectList = countData.stream().map(s->s.getInsectName()).collect(Collectors.toList());
            List<InsectCountDataVO> insectStartTime = insectRecordService.getInsectStartTime(insectList, request);
            Map<String, String> collect =
                    insectStartTime.stream().collect(Collectors.toMap(InsectCountDataVO::getInsectName, InsectCountDataVO::getInsectFirst,(x,y) -> x));
            for (InsectCountDataVO s : insectCountData) {
                s.setInsectFirst(collect.get(s.getInsectName()));
                collect.remove(s.getInsectName());
            }
        }

        //设置结果
        result.setTypeNum(countData.size());
        result.setSumNum(countData.stream().mapToInt(InsectCountDataVO::getNums).sum());

        result.setInsectFirstRecords(warningRecords);
        result.setCountDataVOS(insectCountData);

        return result;
    }

    private String getFactoryKey(Long productId, String factor) {
        String result = "other";

        if(Objects.equals(productId,136L) && Objects.equals(factor,"dct")){
            result = "num1";
        }

        return result;
    }

    @Override
    public List<DeviceFactorDataVO> getBaseData(DeviceFactorDataRequest request){
        return WQRremoteCall.getBaseData(request);
    }
    @Override
    public String exportBaseData(DeviceFactorDataRequest request){

        List<DeviceFactorDataVO> baseData = this.getBaseData(request);

        try {
            // 1.创建一个工作簿。03
            Workbook workbook = new XSSFWorkbook(); // 07和03版本只有对象不同，其他操作一样

            // 2.创建一个工作表
            Sheet sheet = workbook.createSheet("杀虫数据");
            // 3.创建行。第一行 表头
            Row row = sheet.createRow(0);

            // (1,1) 第一行第一列的单元格
            Cell cell = row.createCell(0);
            cell.setCellValue("序号");

            // (1,2) 第一行第二列的单元格
            Cell cell2 = row.createCell(1);
            cell2.setCellValue("时间");

            // 4.创建列。
            for (int i = 0; i < baseData.size(); i++) {
                // (1,1) 第一行第一列的单元格
                Cell nameCell = row.createCell(2 + i);
                nameCell.setCellValue(baseData.get(i).getDeviceId());

                sheet.setColumnWidth(2 + i,(int) ((26 + 0.72) * 256));
            }

            sheet.setColumnWidth(1,(int) ((20 + 0.72) * 256));


            TreeMap<String,Double[]> rowMap = new TreeMap<>();

            //组装每行数据
            for (int i = 0; i < baseData.size(); i++) {
                DeviceFactorDataVO vo = baseData.get(i);

                List<DeviceFactorCountData> countDataList = vo.getCountData();

                for (DeviceFactorCountData countData : countDataList) {
                    Double[] doubles = rowMap.get(countData.getDate());
                    if(doubles == null){
                        doubles = new Double[baseData.size()];
                    }
                    doubles[i] = countData.getDValue() == null ? 0 : countData.getDValue();
                    rowMap.put(countData.getDate(),doubles);
                }
            }

            rowMap.comparator();

            int rowNum = 1;
            for (String rowDate : rowMap.keySet()) {
                Row dataRow = sheet.createRow(rowNum);

                //设置序号
                Cell dataCell01 = dataRow.createCell(0);
                dataCell01.setCellValue(rowNum);

                //设置序号
                Cell dataCell02 = dataRow.createCell(1);
                dataCell02.setCellValue(rowDate);

                rowNum++;

                Double[] doubles = rowMap.get(rowDate);
                for (int i = 0; i < doubles.length; i++) {
                    Double aDouble = doubles[i];
                    Cell dataCell03 = dataRow.createCell(2 + i);
                    dataCell03.setCellValue(aDouble == null ? 0 : aDouble.intValue());
                }
            }

            String filename =  UUID.randomUUID() + "_" + "杀虫数据" + ".xlsx";
            String downloadPath = RuoYiConfig.getDownloadPath() + filename;

            OutputStream out =  new FileOutputStream(downloadPath);

            workbook.write(out);
            out.flush();
            out.close();

            return filename;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    private DeviceFactorDataVO getDeviceFactorDataVO(DeviceAggreDataParam param,FactorInfo factorInfo){

        List<DeviceData> dataWinAvg = influxdb2Service.aggregateWindow(param);

        DeviceFactorDataVO vo = new DeviceFactorDataVO();
        vo.setDeviceId(param.getDeviceId());
        vo.setFactorName(factorInfo.getFactorName());
        vo.setFactorUnit(factorInfo.getFactorUnit());
        vo.setFactorKey(factorInfo.getFactorKey());
        vo.buildCountData(dataWinAvg);

        return vo;
    }

    private DeviceFactorDataVO getDeviceBaseDataVO(DeviceAggreDataParam param,FactorInfo factorInfo){

        List<DeviceData> baseData = influxdb2Service.getBaseHistoryData(param);

        DeviceFactorDataVO vo = new DeviceFactorDataVO();
        vo.setDeviceId(param.getDeviceId());
        vo.setFactorName(factorInfo.getFactorName());
        vo.setFactorUnit(factorInfo.getFactorUnit());
        vo.setFactorKey(factorInfo.getFactorKey());
        vo.buildCountData(baseData,param.getFactor());

        return vo;
    }

    @Override
    public DeviceContrastDataVO getContrastData(DeviceFactorDataRequest request){
        DeviceContrastDataVO vo = new DeviceContrastDataVO();

        List<DeviceFactorDataVO> factorData = this.getFactorData(request);
        vo.setFactorData(factorData);

        if (request.getContrastType().equals(1)){
            request.setFactors(CollUtil.newArrayList(FactorEnum.DCT.getKey()));
            List<DeviceFactorDataVO> lampData = this.getBaseData(request);
            vo.setLampData(lampData);
        }else if (request.getContrastType().equals(2)) {
            InsectListRequest insectListRequest = request.getInsectListRequest();

            //查询账号下的虫情设备
            List<String> insectIds = deviceInfoService.getDeviceNoByCode(FunctionCodeEnum.PRODUCT_INSECT_ID.name());
            insectListRequest.setDeviceIds(insectIds);
            insectListRequest.setInsectName(request.getContrastInsect());

            List<InsectAnalysisVO> insectData = insectRecordService.getCountByInsectName(insectListRequest);
            vo.setInsectData(insectData);
        }

        return vo;
    }

}
